// 
// SoapTrace.Net - A soap message monitoring utility. 
// 
// Copyright (C) 2004 Matthew Ward
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// Matthew Ward (mrward@users.sourceforge.net)
// 

using SoapTrace.Core.Communication;
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using WinPcap;

namespace PacketMonitor
{
	public partial class MainForm : Form
	{
		/// <summary>
		/// The monitoring network interface.
		/// </summary>
		private NetworkInterface m_NetworkInterface;
		
		private RawSocket m_RawSocket;
		private string m_IPAddress = String.Empty;
		
		private const int IOC_VENDOR = 0x18000000;
		private const int IOC_IN = -2147483648; 
		private const int SIO_RCVALL = IOC_IN | IOC_VENDOR | 1;
		
		private NetworkInterfaceCollection m_Devices = new NetworkInterfaceCollection( );
		private IPAddress[ ] m_IPAddresses = new IPAddress[ 0 ];
		
		private delegate void AppendTextHandler( string message );

		public MainForm( )
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent( );

			// Use the first network device.

			m_Devices = NetworkInterface.GetAllNetworkInterfaces( );
			
			if( m_Devices.Count > 0 )
			{
				m_NetworkInterface = m_Devices[ 0 ];
			
				foreach( NetworkInterface Device in m_Devices )
				{
					Device.PacketReceived += new PacketReceivedEventHandler( OnPacketReceived );
				}
				
				m_NetworkInterface.PacketFilter = FilterTextBox.Text;
	
				m_NetworkInterface.Open( );
				
				// Read the raw socket IP addresses for this host.
				
				m_IPAddresses = Dns.Resolve( Dns.GetHostName( ) ).AddressList;
			}
			
			ShowNetworkInterfaces( );
		}

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[ STAThread ]
		static void Main( ) 
		{
			Application.Run( new MainForm( ) );
		}

		/// <summary>
		/// Apply button has been clicked.  Change the server's port and
		/// restart it.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ApplyButton_Click( object sender, EventArgs e )
		{
			try
			{
				// Change filter

				m_NetworkInterface.Close( );
				
				if( m_RawSocket != null )
				{
					m_RawSocket.Close( );
					m_RawSocket = null;
				}
				
				if( UseWinPcapRadioButton.Checked )
				{
					// WinPcap.
					m_NetworkInterface = m_Devices[ NetworkInterfaceComboBox.SelectedIndex ];
					m_NetworkInterface.PacketFilter = FilterTextBox.Text;					
					m_NetworkInterface.Open( );
				}
				else
				{
					// Raw sockets.
					m_RawSocket = new RawSocket( );
					m_RawSocket.PacketReceived += new PacketReceivedEventHandler( OnPacketReceived );
					m_IPAddress = m_IPAddresses[ NetworkInterfaceComboBox.SelectedIndex ].ToString( );
					m_RawSocket.Open( m_IPAddress );
				}

				ApplyButton.Enabled = false;
			}
			catch( WinPcapException Ex )
			{
				MessageBox.Show( Ex.Message );
			}
			catch( SocketException Ex )
			{
				MessageBox.Show( Ex.Message );
			}
		}

		/// <summary>
		/// Handles data packet received event.
		/// </summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		private void OnPacketReceived( object sender, PacketReceivedEventArgs e )
		{
			AppendText( String.Concat( e.Packet.RawHex, "\r\n\r\n" ) );
		}
		
		/// <summary>
		/// Appends the message to the main form's text box.
		/// </summary>
		/// <param name="message">The message.</param>
		private void AppendText( string message )
		{
			if( InvokeRequired )
			{
				AppendTextHandler Handler = new AppendTextHandler( AppendText );
				
				Invoke( Handler, new object[ ] { message } );
			}
			else
			{
				DiagnosticsTextBox.Text += message;
	
				DiagnosticsTextBox.Select( DiagnosticsTextBox.Text.Length, 0 );
				DiagnosticsTextBox.ScrollToCaret( );
			}
		}

		/// <summary>
		/// Main form closed by the user.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void MainForm_Closing( object sender, CancelEventArgs e )
		{
			if( m_NetworkInterface != null )
			{
				m_NetworkInterface.Close( );
			}
			
			if( m_RawSocket != null )
			{
				m_RawSocket.Close( );
			}
		}

		/// <summary>
		/// User changed the filter string.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void FilterTextBox_TextChanged( object sender,EventArgs e )
		{
			ApplyButton.Enabled = IsNetworkDeviceSelected;
		}
		
		private void UseRawSocketsRadioButtonCheckedChanged(object sender, System.EventArgs e)
		{
			ShowNetworkInterfaces( );
			ApplyButton.Enabled = IsNetworkDeviceSelected;	
		}
		
		private void UseWinPcapRadioButtonCheckedChanged(object sender, System.EventArgs e)
		{
			ShowNetworkInterfaces( );
			ApplyButton.Enabled = IsNetworkDeviceSelected;	
		}
		
		private void ShowNetworkInterfaces( )
		{
			NetworkInterfaceComboBox.Items.Clear( );

			if( UseWinPcapRadioButton.Checked )
			{
				int SelectedIndex = -1;
				
				for( int i = 0; i < m_Devices.Count; ++i )
				{
					NetworkInterface Device = m_Devices[ i ];
					NetworkInterfaceComboBox.Items.Add( Device.Description );
					
					if( m_NetworkInterface.Description == Device.Description )
					{
						SelectedIndex = i;
					}
				}
				
				NetworkInterfaceComboBox.SelectedIndex = SelectedIndex;
			}
			else
			{		
				int SelectedIndex = -1;
				for( int i = 0; i < m_IPAddresses.Length; ++i )
				{
					IPAddress Address = m_IPAddresses[ i ];
					NetworkInterfaceComboBox.Items.Add( Address.ToString( ) );
					
					if( m_RawSocket != null )
					{
						if( m_IPAddress == Address.ToString( ) )
						{
							SelectedIndex = i;
						}
					}
				}
				
				NetworkInterfaceComboBox.SelectedIndex = SelectedIndex;
			}
		}
		
		private void NetworkInterfaceComboBoxSelectedIndexChanged(object sender, System.EventArgs e)
		{
			ApplyButton.Enabled = true;
		}
		
		private void ClearButtonClick(object sender, System.EventArgs e)
		{
			DiagnosticsTextBox.Clear( );
		}
		
		private bool IsNetworkDeviceSelected {
			get { return NetworkInterfaceComboBox.SelectedIndex != -1; }
		}
	}
}
